import re

from . import varint
from .SerialTypeCodesFormat import SerialTypeCodesFormat
from .Sqlite3CellReader import Sqlite3CellReader
from .Sqlite3Common import *

'''
已知所要读取的表
删除之前:
    cellsize 不超过页大小，1-2位
    rowid, 不超过2097151， 1-3位
    headersize必只占据一位, 0～127，单条不超过页大小, 不超过63个字段
三者和X占据3-6个字节
    type_i, 叶子页头部最少12，单页大小最大0x8000，type_i占用不可能超过2
    3: 删除后从cellsize位置覆盖到至多type1位置
    4: 相等，各字段数据保存完整
    5: 首个可变长数据占据一位，具有完整header, 值为sum(type_sizes)-1
    6：残缺的rowid，完整的headersize, field_count 个可变长度数据
尝试读取 field_count + 2个数据
    2，2，1的概率应最大，其次1，2，1

'''


class Sqlite3FreeBlockParser:
    def __init__(self, page_data, page_size=DEFAULT_PAGE_SIZE):
        self.page_data = page_data
        self.page_size = page_size
        self.feature = []
        self.field_count = 0

    def set_current_page_feature(self, record):
        if not record and isinstance(record, list):
            return False

        for ele in record:
            if ele and isinstance(ele, str) and re.match(url_parttern, ele):
                break
        else:
            return False

        for ele in record:
            self.feature.append(type(ele))

        self.field_count = len(record)
        return True

    def parse(self):
        res = []
        address_list = self.get_freeblocks_address()
        for address in address_list:
            try:
                record = self._parse_with_feature(address)
                if record:
                    res.append(record)
            except Exception as err:
                # record处理有错误，则丢弃掉整个record
                print(err)

        return res

    def get_freeblocks_address(self):
        # 每个自由块首部2字节数据为下个自由块地址
        # 叶子叶头部最少12字节，偏移不应超过页大小

        address_list = []
        freeblock_address = conver_bytes_to_int(self.page_data[1:3])
        while freeblock_address in range(12, self.page_size) and freeblock_address not in address_list:
            address_list.append(freeblock_address)
            freeblock_address = conver_bytes_to_int(self.page_data[freeblock_address:freeblock_address+2])

        return address_list

    def get_columns_info(self, free_block_address):
        type_values = []  # 保存各字段占用大小
        type_sizes = []  # 保存各字段大小本身占用大小
        already_read_size = 4  # 已读取分析的字段长度，初始为4，下个自由块偏移与当前自由块大小，各占2字节
        max_read = self.field_count + 2
        while True:
            varint_start = free_block_address+already_read_size
            type_i_size, read_size = varint.decode_bytes(self.page_data[varint_start:])
            if read_size > 2 or read_size == 0 or len(type_values) == max_read:
                break
            type_values.append(type_i_size)
            type_sizes.append(read_size)
            already_read_size += read_size

        return type_values, type_sizes

    def feature_parse(self, type_values):
        '''
        简单区分字符串和整型
        None, SerialTypeCodesFormat.SerialTypeMap.keys(), 大于12的奇偶数, 4种特征
        '''
        if not self.feature and len(self.feature) < 3 and str not in self.feature:
            return None

        features = []
        for type_v in type_values:
            features.append(SerialTypeCodesFormat.data_type(type_v))

        min_features = self.feature[1:]
        min_features_length = len(min_features)

        if min_features_length > len(features):
            return None

        i = 0
        for i in range(0, len(features) - min_features_length + 1):
            if compare_list_ignore_NoneType(min_features, features[i:][:min_features_length]):
                break
        else:
            return None

        '''
        i = 0, X = 3
        i = 1, X = 4
        i = 2, X = 5
        i = 3, X = 6
        '''
        tmp_dict = {
            0: 3,
            1: 4,
            2: 5,
            3: 6
        }
        return tmp_dict.get(i, None)

    def _parse_with_feature(self, address):
        # 当前叶子页存在可读cell时，识别各字段依次的类型来匹配判断出完整的cell header后按照常规cell来读取数据
        cellsize = conver_bytes_to_int(self.page_data[address+2:address+4])
        type_values, type_sizes = self.get_columns_info(address)

        if len(type_values) < self.field_count - 1:
            return None

        x_value = self.feature_parse(type_values)
        if not x_value:
            return None

        type_ss = []
        record_data = None
        if x_value == 5:
            if cellsize != x_value + SerialTypeCodesFormat.type_s_sum(type_values[1:self.field_count+1]) \
                    + sum(type_sizes[1:self.field_count+1]):
                return None
            if type_sizes[0] != 1:
                return None
            if sum(type_sizes[:self.field_count+1]) != type_values[0]:
                return None
            print('x_value == 5')
            type_ss = type_values[1:self.field_count+1]
            record_data = self.page_data[address+4+sum(type_sizes[:self.field_count+1]):address+cellsize]
        elif x_value == 4:
            if cellsize != x_value + SerialTypeCodesFormat.type_s_sum(type_values[:self.field_count]) \
                    + sum(type_sizes[:self.field_count]):
                return None
            print('x_value == 4')
            type_ss = type_values[:self.field_count]
            record_data = self.page_data[address+4+sum(type_sizes[:self.field_count]):address+cellsize]
        elif x_value == 3:
            type_1 = cellsize - \
                SerialTypeCodesFormat.type_s_sum(
                    type_values[:self.field_count-1]) + sum(type_sizes[:self.field_count-1])
            print('x_value == 3', type_1)
            type_ss.append(type_1)
            type_ss += type_sizes[:self.field_count-1]
            record_data = self.page_data[address+4+sum(type_sizes[:self.field_count-1]):address+cellsize]
        elif x_value == 6:
            if cellsize != x_value + SerialTypeCodesFormat.type_s_sum(type_values[2:]) + sum(type_sizes[2:]):
                return None
            if type_sizes[0] != 1 or type_sizes[1] != 1:
                return None
            print('x_value == 6')
            type_ss += type_sizes[:self.field_count-1]
            record_data = self.page_data[address+4+sum(type_sizes[:self.field_count-1]):address+cellsize]
        else:
            return None

        if not type_ss or not record_data:
            return None

        record = Sqlite3CellReader().read_data(type_ss, record_data)
        return record
